import requests
from datetime import datetime, timedelta, date
from dateutil.relativedelta import relativedelta
import pandas as pd

class AShareTradingDayChecker:
    """中国A股交易日检查工具"""
    def __init__(self):
        self.cache = {}
        self.holiday_api = "http://tool.bitefu.net/jiari/"
    
    def is_trading_day(self, date: date) -> bool:
        """判断指定日期是否为A股交易日（排除周末和节假日）"""
        if date.weekday() >= 5:  # 排除周末
            return False
        return self._is_working_day(date)
    
    def _is_working_day(self, date: date) -> bool:
        """检查是否为工作日（使用API或备用规则）"""
        date_str = date.strftime("%Y%m%d")
        
        # 优先使用缓存
        if date_str in self.cache:
            return self.cache[date_str]
        
        try:
            # 请求节假日API
            response = requests.get(self.holiday_api, params={"d": date_str})
            if response.status_code == 200:
                result = int(response.text)
                # 0: 工作日, 1: 休息日, 2: 节假日（均非交易日）
                is_working = result == 0
                self.cache[date_str] = is_working
                return is_working
        except Exception as e:
            print(f"节假日API请求失败: {e}")
        
        # API不可用时的备用规则（覆盖常见节假日，需根据实际情况更新）
        return self._fallback_is_working_day(date)
    
    def _fallback_is_working_day(self, date: date) -> bool:
        """备用节假日判断（仅示例，需根据最新放假安排调整）"""
        # 定义常见节假日（月, 日）
        holidays = [
            (1, 1),   # 元旦
            (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7),  # 春节
            (4, 5),   # 清明
            (5, 1),   # 劳动节
            (6, 10), (6, 11), (6, 12),  # 端午（2025年示例，需动态调整）
            (9, 29), (9, 30), (10, 1), (10, 2), (10, 3), (10, 4), (10, 5)  # 中秋国庆（2025年示例）
        ]
        month_day = (date.month, date.day)
        return month_day not in holidays
    
    def get_trading_days(self, start_date: date, end_date: date) -> list[date]:
        """获取指定区间内的所有交易日"""
        trading_days = []
        current_date = start_date
        while current_date <= end_date:
            if self.is_trading_day(current_date):
                trading_days.append(current_date)
            current_date += relativedelta(days=1)
        return trading_days
    

class DeliveryDateCalculator:
    """期货期权交割日计算器"""
    def __init__(self, trading_day_checker):
        self.trading_day_checker = trading_day_checker
    
    def get_monthly_delivery_dates(self, start_date, end_date):
        """获取指定范围内的月度交割日（第三个星期五）"""
        dates = []
        current_date = start_date.replace(day=1)
        
        while current_date <= end_date:
            # 找当月的第三个星期五
            month = current_date.month
            candidate = datetime(current_date.year, month, 1)
            
            friday_count = 0
            while candidate.month == month:
                if candidate.weekday() == 4:  # 星期五
                    friday_count += 1
                    if friday_count == 3:
                        # 检查是否为交易日
                        delivery_date = self._adjust_to_trading_day(candidate.date())
                        if start_date <= delivery_date <= end_date:
                            dates.append(delivery_date)
                        break
                candidate += timedelta(days=1)
            
            current_date += relativedelta(months=1)
        
        return dates
    
    def _adjust_to_trading_day(self, date):
        """调整到最近的交易日"""
        for delta in [0, 1, -1, 2, -2, 3, -3]:
            new_date = date + timedelta(days=delta)
            if self.trading_day_checker.is_trading_day(new_date):
                return new_date
        return date